package com.hi.dhl.console

import com.hi.dhl.common.Common
import com.hi.dhl.common.R
import com.hi.dhl.utils.ExecutableUtils
import com.hi.dhl.utils.FileUtils
import com.intellij.openapi.util.SystemInfoRt
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.runBlockingWithTimeout
import java.io.File

/**
 * <pre>
 *     author: dhl
 *     date  : 2022/9/9
 *     desc  :
 * </pre>
 */
object CommandManager {

    fun compileAndroid(build: StringBuilder,
                       extraCommand: String,
                       projectBasePath: String,
                       remoteMachineInfo: RemoteMachineInfo): StringBuilder {
        val remoteProjectPath = getRemoteMachineWorkPath(projectBasePath, remoteMachineInfo)
        // 同步文件到远程
        syncLocalToRemote(build, remoteProjectPath, projectBasePath, remoteMachineInfo)
        build.append(" && ")
        // 执行编译命令

        // 删除远程apk
        val deleteRemoteApksPath = FileUtils.getShellScriptPath(projectBasePath, R.ShellScript.deleteRemoteApks)
        execRemoteSellScript(build,deleteRemoteApksPath, remoteProjectPath, remoteMachineInfo, projectBasePath)

        execRemoteCommand(build, projectBasePath, remoteProjectPath, extraCommand, remoteMachineInfo)
        build.append(" && ")
        // 将结果拉回到本地
        syncRemoteToLocal(build, remoteProjectPath, projectBasePath, remoteMachineInfo)
        // 执行本地安装命令
        val shellPath = FileUtils.getShellScriptPath(projectBasePath, R.ShellScript.installApk)
        var localRootDir = if (remoteMachineInfo.localRootDir.isNullOrEmpty()) {
            projectBasePath
        } else {
            remoteMachineInfo.localRootDir
        }
        if (FileUtils.isExists(shellPath)) {
            build.append(" && ")

            var execShellScript = ""
            if (!remoteMachineInfo.launchActivity.isNullOrEmpty()
                && !remoteMachineInfo.launchActivity.equals(R.String.ui.tfLaunchActivity)) {
                execShellScript = "chmod 777 ${shellPath} && bash ${shellPath} ${remoteMachineInfo.launchActivity} ${localRootDir} ${remoteMachineInfo.remoteBuildCommand}"
            } else {
                execShellScript = "chmod 777 ${shellPath} && bash ${shellPath} "
            }

            execLocalCommand(build, execShellScript)
        }
        killSSH(build, projectBasePath , extraCommand)
        return build
    }

    fun getRemoteRootDir(localProjectBasePath: String, remoteMachineInfo: RemoteMachineInfo): String {
        return if(remoteMachineInfo.localRootDir.isNullOrEmpty()) {
            val projectName = localProjectBasePath.substring(localProjectBasePath.lastIndexOf(File.separator) + 1)
            remoteMachineInfo.remoteRootDir + File.separator + projectName + File.separator
        } else {
            val localRootDir = remoteMachineInfo.localRootDir
            val rootName = localRootDir!!.substring(localRootDir.lastIndexOf(File.separator) + 1)
            remoteMachineInfo.remoteRootDir + File.separator + rootName + File.separator
        }
    }

    fun getRemoteMachineWorkPath(localProjectBasePath: String, remoteMachineInfo: RemoteMachineInfo): String {
        return if (remoteMachineInfo.localRootDir.isNullOrEmpty()) {
            val projectName = localProjectBasePath.substring(localProjectBasePath.lastIndexOf(File.separator) + 1)
            remoteMachineInfo.remoteRootDir + File.separator + projectName + File.separator
        } else {
            val localRootDir = remoteMachineInfo.localRootDir!!
            val rootName = localRootDir!!.substring(localRootDir.lastIndexOf(File.separator) + 1)
            val projectName = localProjectBasePath.replace(localRootDir, "").removePrefix(File.separator)
            remoteMachineInfo.remoteRootDir + File.separator + rootName + File.separator + projectName + File.separator
        }
    }

    fun syncLocalToRemote(build: StringBuilder,
                          remoteMachineWorkPath: String,
                          localProjectBasePath: String,
                          remoteMachineInfo: RemoteMachineInfo) {

        var remoteRootDir = getRemoteRootDir(localProjectBasePath, remoteMachineInfo)
        var localRootDir = if (remoteMachineInfo.localRootDir.isNullOrEmpty()) {
            localProjectBasePath
        } else {
            remoteMachineInfo.localRootDir
        }

//        /bin/bash -c "rsync -e 'ssh -p 22' --archive --delete  --progress --rsync-path='mkdir -p ~/rsync/demo && rsync'  ./ root@ip:~/rsync/demo"
        build.append("${execSshpassScriptCommand(localProjectBasePath, remoteMachineInfo)}  rsync -e 'ssh -p ${remoteMachineInfo.remotePort}  -o StrictHostKeyChecking=no' --archive --delete ")
//        build.append("--partial ") // 保留因故没有传完的文件，下次在续传
        build.append("--progress ")
        var sdkdir: String = ""
        if(!remoteMachineInfo.sdkDir.isNullOrEmpty()
            && !remoteMachineInfo.sdkDir.equals(R.String.ui.tfSDK)){
            sdkdir = ";echo sdk.dir=${remoteMachineInfo.sdkDir} >> ${remoteMachineWorkPath + File.separator + Common.localProperties}"
        }
        var ndkDir: String = ""
        if(!remoteMachineInfo.ndkDir.isNullOrEmpty()
            && !remoteMachineInfo.ndkDir.equals(R.String.ui.tfNDK)){
            ndkDir = ";echo ndk.dir=${remoteMachineInfo.ndkDir} >> ${remoteMachineWorkPath + File.separator + Common.localProperties}"
        }
        build.append("--rsync-path='export LC_ALL=en_US.UTF-8;export LANG=en_US.UTF-8;mkdir -p ${remoteMachineWorkPath};rm -rf ${remoteMachineWorkPath + File.separator + Common.localProperties}${sdkdir}${ndkDir} && rsync' ")
        val localIgnoreFile =
            File(localProjectBasePath + File.separator + Common.syncConfigRootDir + File.separator + Common.syncConfigLocalIgnoreFile)
        if (localIgnoreFile.exists()) {
            build.append("--exclude-from=${localIgnoreFile}  ")
        }
        build.append("${localRootDir + File.separator} ")
        build.append(" ${remoteMachineInfo.remoteUser}@${remoteMachineInfo.remoteHost}:${remoteRootDir} ")
    }

    fun syncLocalFileToRemote(build: StringBuilder,
                              filePath: String,
                              remoteMachineWorkPath: String,
                              remoteMachineInfo: RemoteMachineInfo,
                              localProjectBasePath: String) {
        build.append("${execSshpassScriptCommand(localProjectBasePath, remoteMachineInfo)}  rsync -e 'ssh -p ${remoteMachineInfo.remotePort} -o StrictHostKeyChecking=no' --archive --delete ")
        build.append("--progress ")
        build.append("--rsync-path='export LC_ALL=en_US.UTF-8;export LANG=en_US.UTF-8;mkdir -p ${remoteMachineWorkPath} && rsync' ")
        build.append("${filePath} ")
        build.append(" ${remoteMachineInfo.remoteUser}@${remoteMachineInfo.remoteHost}:${remoteMachineWorkPath} ")
    }

    fun execRemoteCommand(build: StringBuilder,
                          localProjectBasePath: String,
                          remoteMachineWorkPath: String,
                          extraCommand: String,
                          remoteMachineInfo: RemoteMachineInfo) {
//        ssh -p22 root@ip  "cd ~/SyncKit  && "
        build.append("${execSshpassScriptCommand(localProjectBasePath, remoteMachineInfo)} ssh -p ${remoteMachineInfo.remotePort}  -o StrictHostKeyChecking=no ${remoteMachineInfo.remoteUser}@${remoteMachineInfo.remoteHost}  ' set +e;source  ~/.bashrc > /dev/null 2>&1; source ~/.bash_profile > /dev/null 2>&1; source ~/.zshrc > /dev/null 2>&1;cd ${remoteMachineWorkPath}  && ${extraCommand}'")
    }

    fun killSSH(build: StringBuilder,localProjectBasePath: String, extraCommand: String) {
        val killSshPath = FileUtils.getShellScriptPath(localProjectBasePath, R.ShellScript.killSsh)
        if (FileUtils.isExists(killSshPath)) {
            build.append(" && ")
            var execShellScript = "chmod 777 $killSshPath && bash $killSshPath '${extraCommand}'"
            execLocalCommand(build, execShellScript)
        }
    }

    fun execRemoteSellScript(build: StringBuilder,
                             filePath: String,
                             remoteMachineWorkPath: String,
                             remoteMachineInfo: RemoteMachineInfo,
                             localProjectBasePath: String) {
        val remoteScriptDirPath = remoteMachineWorkPath + File.separator + Common.syncConfigRootDir + File.separator + Common.syncConfigScriptDir
        syncLocalFileToRemote(build, filePath, remoteScriptDirPath, remoteMachineInfo, localProjectBasePath)
        build.append(" && ")
        val fileName = filePath.substring(filePath.lastIndexOf(File.separator) + 1)
        val remoteScriptPath = remoteScriptDirPath + File.separator + fileName
        val exePath = ExecutableUtils.findExecutableInServiceOnPath()
        val execShellScript: String
        if(filePath.contains(R.ShellScript.installSSHPub) && !remoteMachineInfo.sshPublicKey.isNullOrEmpty()){
            execShellScript = "chmod 777 ${remoteScriptPath} && ${exePath} ${remoteScriptPath} ${remoteMachineInfo.sshPublicKey} "
        }else {
            execShellScript = "chmod 777 ${remoteScriptPath} && ${exePath} ${remoteScriptPath} "
        }
        execRemoteCommand(build, localProjectBasePath, remoteMachineWorkPath, execShellScript, remoteMachineInfo)
    }

    private fun syncRemoteToLocal(build: StringBuilder,
                                  remoteMachineWorkPath: String,
                                  localProjectBasePath: String,
                                  remoteMachineInfo: RemoteMachineInfo) {

        var remoteRootDir = getRemoteRootDir(localProjectBasePath, remoteMachineInfo)
        var localRootDir = if (remoteMachineInfo.localRootDir.isNullOrEmpty()) {
            localProjectBasePath
        } else {
            remoteMachineInfo.localRootDir
        }

        build.append("${execSshpassScriptCommand(localProjectBasePath, remoteMachineInfo)} rsync -e 'ssh -p ${remoteMachineInfo.remotePort} -o StrictHostKeyChecking=no' --archive ")
//        build.append("--partial ") // 保留因故没有传完的文件，下次在续传
        build.append("--progress ")
        val remoteIncludeFile =
            File(localProjectBasePath + File.separator + Common.syncConfigRootDir + File.separator + Common.syncConfigRemoteIncludeFile)
        if (remoteIncludeFile.exists()) {
            build.append("--include-from=${remoteIncludeFile}  ")
        }

        val remoteIgnoreFile =
            File(localProjectBasePath + File.separator + Common.syncConfigRootDir + File.separator + Common.syncConfigRemoteIgnoreFile)
        if (remoteIgnoreFile.exists()) {
            build.append("--exclude-from=${remoteIgnoreFile}  ")
        }
        
        build.append(" ${remoteMachineInfo.remoteUser}@${remoteMachineInfo.remoteHost}:${remoteRootDir} ")
        build.append("$localRootDir ")
    }

    fun execLocalCommand(build: StringBuilder, extraCommand: String) {
        build.append(extraCommand)
    }

    fun execSshpassScriptCommand(
        localProjectBasePath: String,
        remoteMachineInfo: RemoteMachineInfo
    ): String {
        if (SystemInfoRt.isWindows) {
            return ""
        }
        val shellInstallSshpass = FileUtils.getShellScriptPath(localProjectBasePath, R.ShellScript.installSshpass)
        val password = remoteMachineInfo.remoteUserPassword
        if (password.isNullOrEmpty()
            || password.equals(R.String.ui.tfRemotePassword)) {
            return ""
        } else {
            return "set +e;chmod 777 ${shellInstallSshpass} && bash ${shellInstallSshpass}; ${getSshpassPath()}  -p  '${remoteMachineInfo.remoteUserPassword}'  "
        }
    }

    fun getSshpassPath() = "/usr/local/bin/sshpass"

    fun makeSshpassCommand(remoteMachineInfo: RemoteMachineInfo): String{
        if (SystemInfoRt.isWindows) {
            return ""
        }
        val password = remoteMachineInfo.remoteUserPassword
        if (password.isNullOrEmpty() ||
            password.equals(R.String.ui.tfRemotePassword)
        ) {
            return ""
        } else {
            return "${getSshpassPath()}  -p  '${remoteMachineInfo.remoteUserPassword}'  "
        }
    }

}